/* src/interfaces/ecpg/preproc/variable.c */

#include "postgres_fe.h"

#include "preproc_extern.h"

static struct variable *allvariables = NULL;

struct variable * new_variable(const char *fc_name, struct ECPGtype *fc_type, int fc_brace_level)
{
	struct variable *fc_p = (struct variable *) mm_alloc(sizeof(struct variable));

	fc_p->name = mm_strdup(fc_name);
	fc_p->type = fc_type;
	fc_p->brace_level = fc_brace_level;

	fc_p->next = allvariables;
	allvariables = fc_p;

	return fc_p;
}

static struct variable * fc_find_struct_member(char *fc_name, char *fc_str, struct ECPGstruct_member *fc_members, int fc_brace_level)
{
	char	   *fc_next = strpbrk(++fc_str, ".-["),
			   *fc_end,
				fc_c = '\0';

	if (fc_next != NULL)
	{
		fc_c = *fc_next;
		*fc_next = '\0';
	}

	for (; fc_members; fc_members = fc_members->next)
	{
		if (strcmp(fc_members->name, fc_str) == 0)
		{
			if (fc_next == NULL)
			{
				/* 找到了结束 */
				switch (fc_members->type->type)
				{
					case ECPGt_array:
						return new_variable(fc_name, ECPGmake_array_type(ECPGmake_simple_type(fc_members->type->u.element->type, fc_members->type->u.element->size, fc_members->type->u.element->counter), fc_members->type->size), fc_brace_level);
					case ECPGt_struct:
					case ECPGt_union:
						return new_variable(fc_name, ECPGmake_struct_type(fc_members->type->u.members, fc_members->type->type, fc_members->type->type_name, fc_members->type->struct_sizeof), fc_brace_level);
					default:
						return new_variable(fc_name, ECPGmake_simple_type(fc_members->type->type, fc_members->type->size, fc_members->type->counter), fc_brace_level);
				}
			}
			else
			{
				*fc_next = fc_c;
				if (fc_c == '[')
				{
					int			fc_count;

					/*
					 * 我们不关心数组括号内的内容，所以
					 * 就把字符吞掉
					 */
					for (fc_count = 1, fc_end = fc_next + 1; fc_count; fc_end++)
					{
						switch (*fc_end)
						{
							case '[':
								fc_count++;
								break;
							case ']':
								fc_count--;
								break;
							default:
								break;
						}
					}
				}
				else
					fc_end = fc_next;

				switch (*fc_end)
				{
					case '\0':	/* 找到了结束，但这次它必须是
								 * 一个数组元素 */
						if (fc_members->type->type != ECPGt_array)
							mmfatal(PARSE_ERROR, "incorrectly formed variable \"%s\"", fc_name);

						switch (fc_members->type->u.element->type)
						{
							case ECPGt_array:
								return new_variable(fc_name, ECPGmake_array_type(ECPGmake_simple_type(fc_members->type->u.element->u.element->type, fc_members->type->u.element->u.element->size, fc_members->type->u.element->u.element->counter), fc_members->type->u.element->size), fc_brace_level);
							case ECPGt_struct:
							case ECPGt_union:
								return new_variable(fc_name, ECPGmake_struct_type(fc_members->type->u.element->u.members, fc_members->type->u.element->type, fc_members->type->u.element->type_name, fc_members->type->u.element->struct_sizeof), fc_brace_level);
							default:
								return new_variable(fc_name, ECPGmake_simple_type(fc_members->type->u.element->type, fc_members->type->u.element->size, fc_members->type->u.element->counter), fc_brace_level);
						}
						break;
					case '-':
						if (fc_members->type->type == ECPGt_array)
							return fc_find_struct_member(fc_name, ++fc_end, fc_members->type->u.element->u.members, fc_brace_level);
						else
							return fc_find_struct_member(fc_name, ++fc_end, fc_members->type->u.members, fc_brace_level);
						break;
					case '.':
						if (fc_members->type->type == ECPGt_array)
							return fc_find_struct_member(fc_name, fc_end, fc_members->type->u.element->u.members, fc_brace_level);
						else
							return fc_find_struct_member(fc_name, fc_end, fc_members->type->u.members, fc_brace_level);
						break;
					default:
						mmfatal(PARSE_ERROR, "incorrectly formed variable \"%s\"", fc_name);
						break;
				}
			}
		}
	}

	return NULL;
}

static struct variable * fc_find_struct(char *fc_name, char *fc_next, char *fc_end)
{
	struct variable *fc_p;
	char		fc_c = *fc_next;

	/* 首先获取母结构条目 */
	*fc_next = '\0';
	fc_p = find_variable(fc_name);

	if (fc_c == '-')
	{
		if (fc_p->type->type != ECPGt_array)
			mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer", fc_name);

		if (fc_p->type->u.element->type != ECPGt_struct && fc_p->type->u.element->type != ECPGt_union)
			mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer to a structure or a union", fc_name);

		/* 恢复名称，我们稍后会需要它 */
		*fc_next = fc_c;

		return fc_find_struct_member(fc_name, ++fc_end, fc_p->type->u.element->u.members, fc_p->brace_level);
	}
	else
	{
		if (fc_next == fc_end)
		{
			if (fc_p->type->type != ECPGt_struct && fc_p->type->type != ECPGt_union)
				mmfatal(PARSE_ERROR, "variable \"%s\" is neither a structure nor a union", fc_name);

			/* 恢复名称，我们稍后会需要它 */
			*fc_next = fc_c;

			return fc_find_struct_member(fc_name, fc_end, fc_p->type->u.members, fc_p->brace_level);
		}
		else
		{
			if (fc_p->type->type != ECPGt_array)
				mmfatal(PARSE_ERROR, "variable \"%s\" is not an array", fc_name);

			if (fc_p->type->u.element->type != ECPGt_struct && fc_p->type->u.element->type != ECPGt_union)
				mmfatal(PARSE_ERROR, "variable \"%s\" is not a pointer to a structure or a union", fc_name);

			/* 恢复名称，我们稍后会需要它 */
			*fc_next = fc_c;

			return fc_find_struct_member(fc_name, fc_end, fc_p->type->u.element->u.members, fc_p->brace_level);
		}
	}
}

static struct variable * fc_find_simple(char *fc_name)
{
	struct variable *fc_p;

	for (fc_p = allvariables; fc_p; fc_p = fc_p->next)
	{
		if (strcmp(fc_p->name, fc_name) == 0)
			return fc_p;
	}

	return NULL;
}

/* 注意，如果遇到未知的 */
/* 变量，该函数将结束程序 */
struct variable * find_variable(char *fc_name)
{
	char	   *fc_next,
			   *fc_end;
	struct variable *fc_p;
	int			fc_count;

	fc_next = strpbrk(fc_name, ".[-");
	if (fc_next)
	{
		if (*fc_next == '[')
		{
			/*
			 * 我们不关心数组括号内的内容，所以就把
			 * 字符吞掉
			 */
			for (fc_count = 1, fc_end = fc_next + 1; fc_count; fc_end++)
			{
				switch (*fc_end)
				{
					case '[':
						fc_count++;
						break;
					case ']':
						fc_count--;
						break;
					default:
						break;
				}
			}
			if (*fc_end == '.')
				fc_p = fc_find_struct(fc_name, fc_next, fc_end);
			else
			{
				char		fc_c = *fc_next;

				*fc_next = '\0';
				fc_p = fc_find_simple(fc_name);
				if (fc_p == NULL)
					mmfatal(PARSE_ERROR, "variable \"%s\" is not declared", fc_name);

				*fc_next = fc_c;
				switch (fc_p->type->u.element->type)
				{
					case ECPGt_array:
						return new_variable(fc_name, ECPGmake_array_type(ECPGmake_simple_type(fc_p->type->u.element->u.element->type, fc_p->type->u.element->u.element->size, fc_p->type->u.element->u.element->counter), fc_p->type->u.element->size), fc_p->brace_level);
					case ECPGt_struct:
					case ECPGt_union:
						return new_variable(fc_name, ECPGmake_struct_type(fc_p->type->u.element->u.members, fc_p->type->u.element->type, fc_p->type->u.element->type_name, fc_p->type->u.element->struct_sizeof), fc_p->brace_level);
					default:
						return new_variable(fc_name, ECPGmake_simple_type(fc_p->type->u.element->type, fc_p->type->u.element->size, fc_p->type->u.element->counter), fc_p->brace_level);
				}
			}
		}
		else
			fc_p = fc_find_struct(fc_name, fc_next, fc_next);
	}
	else
		fc_p = fc_find_simple(fc_name);

	if (fc_p == NULL)
		mmfatal(PARSE_ERROR, "variable \"%s\" is not declared", fc_name);

	return fc_p;
}

void remove_typedefs(int fc_brace_level)
{
	struct typedefs *fc_p,
			   *fc_prev,
			   *fc_next;

	for (fc_p = types, fc_prev = NULL; fc_p; fc_p = fc_next)
	{
		fc_next = fc_p->next;
		if (fc_p->brace_level >= fc_brace_level)
		{
			/* 删除它 */
			if (fc_prev)
				fc_prev->next = fc_next;
			else
				types = fc_next;

			if (fc_p->type->type_enum == ECPGt_struct || fc_p->type->type_enum == ECPGt_union)
				free(fc_p->struct_member_list);
			free(fc_p->type);
			free(fc_p->name);
			free(fc_p);
		}
		else
			fc_prev = fc_p;
	}
}

void remove_variables(int fc_brace_level)
{
	struct variable *fc_p,
			   *fc_prev,
			   *fc_next;

	for (fc_p = allvariables, fc_prev = NULL; fc_p; fc_p = fc_next)
	{
		fc_next = fc_p->next;
		if (fc_p->brace_level >= fc_brace_level)
		{
			/* 删除它，但首先要从光标中删除任何引用 */
			struct cursor *fc_ptr;

			for (fc_ptr = cur; fc_ptr != NULL; fc_ptr = fc_ptr->next)
			{
				struct arguments *fc_varptr,
						   *fc_prevvar,
						   *fc_nextvar;

				for (fc_varptr = fc_ptr->argsinsert, fc_prevvar = NULL;
					 fc_varptr != NULL; fc_varptr = fc_nextvar)
				{
					fc_nextvar = fc_varptr->next;
					if (fc_p == fc_varptr->variable)
					{
						/* 从列表中删除 */
						if (fc_prevvar)
							fc_prevvar->next = fc_nextvar;
						else
							fc_ptr->argsinsert = fc_nextvar;
					}
					else
						fc_prevvar = fc_varptr;
				}
				for (fc_varptr = fc_ptr->argsresult, fc_prevvar = NULL;
					 fc_varptr != NULL; fc_varptr = fc_nextvar)
				{
					fc_nextvar = fc_varptr->next;
					if (fc_p == fc_varptr->variable)
					{
						/* 从列表中删除 */
						if (fc_prevvar)
							fc_prevvar->next = fc_nextvar;
						else
							fc_ptr->argsresult = fc_nextvar;
					}
					else
						fc_prevvar = fc_varptr;
				}
			}

			/* 删除它 */
			if (fc_prev)
				fc_prev->next = fc_next;
			else
				allvariables = fc_next;

			ECPGfree_type(fc_p->type);
			free(fc_p->name);
			free(fc_p);
		}
		else
			fc_prev = fc_p;
	}
}


/*
 * 这里是每个请求都需要处理的变量。
 * 这些变量分为两种：输入和输出。
 * 我会为它们制作两个列表。
 */

struct arguments *argsinsert = NULL;
struct arguments *argsresult = NULL;

void reset_variables(void)
{
	argsinsert = NULL;
	argsresult = NULL;
}

/* 将一个新变量插入到我们的请求列表中。
 * 注意：列表是从末尾转储的，
 * 所以我们必须将新条目添加到开头 */
void add_variable_to_head(struct arguments **fc_list, struct variable *fc_var, struct variable *fc_ind)
{
	struct arguments *fc_p = (struct arguments *) mm_alloc(sizeof(struct arguments));

	fc_p->variable = fc_var;
	fc_p->indicator = fc_ind;
	fc_p->next = *fc_list;
	*fc_list = fc_p;
}

/* 将一个新变量附加到我们的请求列表。 */
void add_variable_to_tail(struct arguments **fc_list, struct variable *fc_var, struct variable *fc_ind)
{
	struct arguments *fc_p,
			   *fc_new = (struct arguments *) mm_alloc(sizeof(struct arguments));

	for (fc_p = *fc_list; fc_p && fc_p->next; fc_p = fc_p->next);

	fc_new->variable = fc_var;
	fc_new->indicator = fc_ind;
	fc_new->next = NULL;

	if (fc_p)
		fc_p->next = fc_new;
	else
		*fc_list = fc_new;
}

void remove_variable_from_list(struct arguments **fc_list, struct variable *fc_var)
{
	struct arguments *fc_p,
			   *fc_prev = NULL;
	bool		fc_found = false;

	for (fc_p = *fc_list; fc_p; fc_p = fc_p->next)
	{
		if (fc_p->variable == fc_var)
		{
			fc_found = true;
			break;
		}
		fc_prev = fc_p;
	}
	if (fc_found)
	{
		if (fc_prev)
			fc_prev->next = fc_p->next;
		else
			*fc_list = fc_p->next;
	}
}

/* 转储该列表中所有变量的列表。
   这是一个递归函数，从列表的末尾开始工作，并
   在继续的过程中删除列表。
 */
void dump_variables(struct arguments *fc_list, int fc_mode)
{
	char	   *fc_str_zero;

	if (fc_list == NULL)
		return;

	fc_str_zero = mm_strdup("0");

	/*
	 * 列表是从开头构建的，所以先转储列表的末尾：
	 */

	dump_variables(fc_list->next, fc_mode);

	/* 然后是当前元素及其指示符 */
	ECPGdump_a_type(base_yyout, fc_list->variable->name, fc_list->variable->type, fc_list->variable->brace_level,
					fc_list->indicator->name, fc_list->indicator->type, fc_list->indicator->brace_level,
					NULL, NULL, fc_str_zero, NULL, NULL);

	/* 然后释放列表元素。 */
	if (fc_mode != 0)
		free(fc_list);

	free(fc_str_zero);
}

void check_indicator(struct ECPGtype *fc_var)
{
	/* 确保这是一个有效的指示符变量 */
	switch (fc_var->type)
	{
			struct ECPGstruct_member *fc_p;

		case ECPGt_short:
		case ECPGt_int:
		case ECPGt_long:
		case ECPGt_long_long:
		case ECPGt_unsigned_short:
		case ECPGt_unsigned_int:
		case ECPGt_unsigned_long:
		case ECPGt_unsigned_long_long:
			break;

		case ECPGt_struct:
		case ECPGt_union:
			for (fc_p = fc_var->u.members; fc_p; fc_p = fc_p->next)
				check_indicator(fc_p->type);
			break;

		case ECPGt_array:
			check_indicator(fc_var->u.element);
			break;
		default:
			mmerror(PARSE_ERROR, ET_ERROR, "indicator variable must have an integer type");
			break;
	}
}

struct typedefs *
get_typedef(char *fc_name)
{
	struct typedefs *fc_this;

	for (fc_this = types; fc_this && strcmp(fc_this->name, fc_name) != 0; fc_this = fc_this->next);
	if (!fc_this)
		mmfatal(PARSE_ERROR, "unrecognized data type name \"%s\"", fc_name);

	return fc_this;
}

void adjust_array(enum ECPGttype fc_type_enum, char **fc_dimension, char **fc_length, char *fc_type_dimension, char *fc_type_index, int fc_pointer_len, bool fc_type_definition)
{
	if (atoi(fc_type_index) >= 0)
	{
		if (atoi(*fc_length) >= 0)
			mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");

		*fc_length = fc_type_index;
	}

	if (atoi(fc_type_dimension) >= 0)
	{
		if (atoi(*fc_dimension) >= 0 && atoi(*fc_length) >= 0)
			mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");

		if (atoi(*fc_dimension) >= 0)
			*fc_length = *fc_dimension;

		*fc_dimension = fc_type_dimension;
	}

	if (fc_pointer_len > 2)
		mmfatal(PARSE_ERROR, ngettext("multilevel pointers (more than 2 levels) are not supported; found %d level",
									  "multilevel pointers (more than 2 levels) are not supported; found %d levels", fc_pointer_len),
				fc_pointer_len);

	if (fc_pointer_len > 1 && fc_type_enum != ECPGt_char && fc_type_enum != ECPGt_unsigned_char && fc_type_enum != ECPGt_string)
		mmfatal(PARSE_ERROR, "pointer to pointer is not supported for this data type");

	if (fc_pointer_len > 1 && (atoi(*fc_length) >= 0 || atoi(*fc_dimension) >= 0))
		mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");

	if (atoi(*fc_length) >= 0 && atoi(*fc_dimension) >= 0 && fc_pointer_len)
		mmfatal(PARSE_ERROR, "multidimensional arrays are not supported");

	switch (fc_type_enum)
	{
		case ECPGt_struct:
		case ECPGt_union:
			/* 指针必须获得维度 0 */
			if (fc_pointer_len)
			{
				*fc_length = *fc_dimension;
				*fc_dimension = mm_strdup("0");
			}

			if (atoi(*fc_length) >= 0)
				mmfatal(PARSE_ERROR, "multidimensional arrays for structures are not supported");

			break;
		case ECPGt_varchar:
		case ECPGt_bytea:
			/* 指针必须获得维度 0 */
			if (fc_pointer_len)
				*fc_dimension = mm_strdup("0");

			/* 一个索引是字符串长度 */
			if (atoi(*fc_length) < 0)
			{
				*fc_length = *fc_dimension;
				*fc_dimension = mm_strdup("-1");
			}

			break;
		case ECPGt_char:
		case ECPGt_unsigned_char:
		case ECPGt_string:
			/* char ** */
			if (fc_pointer_len == 2)
			{
				*fc_length = *fc_dimension = mm_strdup("0");
				break;
			}

			/* 指针必须获得长度 0 */
			if (fc_pointer_len == 1)
				*fc_length = mm_strdup("0");

			/* 一个索引是字符串长度 */
			if (atoi(*fc_length) < 0)
			{
				/*
				 * 确保我们返回长度 = -1 对于没有给定
				 * 界限的数组
				 */
				if (atoi(*fc_dimension) < 0 && !fc_type_definition)

					/*
					 * 不要为 typedef 改变这个，因为在
					 * 变量定义时会被改变
					 */
					*fc_length = mm_strdup("1");
				else if (strcmp(*fc_dimension, "0") == 0)
					*fc_length = mm_strdup("-1");
				else
					*fc_length = *fc_dimension;

				*fc_dimension = mm_strdup("-1");
			}
			break;
		default:
			/* 指针的维度 = 0 */
			if (fc_pointer_len)
			{
				*fc_length = *fc_dimension;
				*fc_dimension = mm_strdup("0");
			}

			if (atoi(*fc_length) >= 0)
				mmfatal(PARSE_ERROR, "multidimensional arrays for simple data types are not supported");

			break;
	}
}
